package br.com.leopard.erp.gym.bean.generic;

import java.util.List;

import javax.faces.bean.ManagedProperty;
import javax.faces.event.ActionEvent;

import org.primefaces.component.panel.Panel;
import org.primefaces.component.selectonemenu.SelectOneMenu;

import br.com.leopard.erp.gym.filtragem.classe.CoreConstrucaoFiltragem;
import br.com.leopard.erp.gym.filtragem.classe.RecuperarFiltrosClasse;
import br.com.leopard.erp.gym.mapeamento.base_sistema.AbstractPersistenceClass;
import br.com.leopard.erp.gym.negocio.AbstractNegocio;
import br.com.leopard.erp.gym.negocio.excessoes.CRUDException;
import br.com.leopard.erp.gym.web.session.CRUDSession;
import br.com.leopard.erp.gym.web.session.UsuarioNavegacaoSession;
import br.com.leopard.erp.gym.web.util.GerarCaminhoPaginaUtil;
import br.com.leopard.erp.gym.web.util.JSFMessageUtil;
import br.com.leopard.erp.gym.web.util.StatusPagina;
import br.com.leopard.erp.gym.web.util.TipoPagina;

public class AbstractCRUDBean<T extends AbstractPersistenceClass, PK> {

	@ManagedProperty(value = "#{usuarioNavegacaoSession}")
	private UsuarioNavegacaoSession navegacaoSession;

	@ManagedProperty(value = "#{CRUDSession}")
	private CRUDSession crudSession;

	private Panel filtragem;

	private SelectOneMenu selectOneMenu;

	private AbstractNegocio<T, PK> negocio;

	private StatusPagina status;

	private Integer quantidadeRegistrosPorPagina;

	private Integer paginaAtual;

	private Long quantidadeRegistrosEncontrados;

	private Long quantidadeRegistrosAtivos;

	private Long quantidadeRegistrosInativos;

	private List<T> registrosEncontrados;

	private T registroSelecionado;

	private Class<T> classe;

	public AbstractCRUDBean(Class<T> classe) {
		super();
		this.classe = classe;
		status = StatusPagina.LISTAR;

		RecuperarFiltrosClasse classeAnotadaProcessamento = new RecuperarFiltrosClasse();
		if (classeAnotadaProcessamento.isClasseAnotadaParaFiltragem(classe)) {
			CoreConstrucaoFiltragem recuperar = new CoreConstrucaoFiltragem();
			filtragem = recuperar.construirPainelFiltro(classe);
		}
	}

	private void resetarValores() {
		status = StatusPagina.LISTAR;

		paginaAtual = 0;
		registroSelecionado = null;
		quantidadeRegistrosPorPagina = 50000;
		paginaAtual = 0;
		quantidadeRegistrosEncontrados = negocio.getCount();
		quantidadeRegistrosAtivos = negocio.getCountAtivos();
		quantidadeRegistrosInativos = negocio.getCountInativos();
	}

	public void acessarPaginaListagem(ActionEvent event) {
		procedimentosAntesAcessarListagem();

		crudSession.setCrudEmExibicao(this);

		navegacaoSession.setCurrentPageContent(GerarCaminhoPaginaUtil.gerarCaminhoPaginaPrincipal(classe, TipoPagina.CRUD));

		resetarValores();

		status = StatusPagina.LISTAR;
		filtrarActionEvent(event);
	}

	public void acessarPaginaCadastro(ActionEvent event) {
		try {
			status = StatusPagina.CADASTRAR;

			registroSelecionado = classe.newInstance();

			registrosEncontrados = null;

			procedimentosAntesAcessarCRUD();
			crudSession.setCrudEmExibicao(this);
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	protected void procedimentosAntesAcessarCRUD() {
	}

	protected void procedimentosAntesAcessarListagem() {
	}

	public void salvarActionEvent(ActionEvent event) {
		try {
			crudSession.setCrudEmExibicao(this);

			if (this.status == StatusPagina.CADASTRAR) {
				negocio.save(registroSelecionado);
			}

			if (this.status == StatusPagina.EDITAR) {
				negocio.editar(registroSelecionado);
			}

			JSFMessageUtil.sendInfoMessageToUser("Registro salvo com sucesso!");
			this.resetarValores();
			this.acessarPaginaListagem(event);
		} catch (CRUDException e) {
			JSFMessageUtil.sendErrorMessageToUser(e.getMensagem());
		}
	}

	public void ativar(ActionEvent event) {
		negocio.ativar(registroSelecionado);
		this.quantidadeRegistrosAtivos++;
		this.quantidadeRegistrosInativos--;

		registroSelecionado = null;
		filtrarActionEvent(event);

		JSFMessageUtil.sendInfoMessageToUser("Registro ativado com sucesso!");
	}

	public void filtrarActionEvent(ActionEvent event) {
		registrosEncontrados = negocio.listAllLimited(quantidadeRegistrosPorPagina);
	}

	public void desativar(ActionEvent event) {
		negocio.inativar(registroSelecionado);
		this.quantidadeRegistrosAtivos--;
		this.quantidadeRegistrosInativos++;

		registroSelecionado = null;
		filtrarActionEvent(event);

		JSFMessageUtil.sendInfoMessageToUser("Registro inativado com sucesso!");
	}

	public void remover(ActionEvent event) {
		try {
			quantidadeRegistrosEncontrados--;

			if (registroSelecionado.getAtivo()) {
				this.quantidadeRegistrosAtivos--;
			} else {
				this.quantidadeRegistrosInativos--;
			}

			this.registrosEncontrados.remove(registroSelecionado);
			negocio.remover(registroSelecionado);
			registroSelecionado = null;

			JSFMessageUtil.sendInfoMessageToUser("Registro excluido com sucesso!");
		} catch (CRUDException e) {
			JSFMessageUtil.sendErrorMessageToUser(e.getMensagem());
		}

	}

	public Boolean isOpcaoEditarDisabled() {
		if (this.registroSelecionado == null) {
			return true;
		}

		return false;
	}

	public Boolean isOpcaoExcluirDisabled() {
		return isOpcaoEditarDisabled();
	}

	public boolean isListagemRendered() {
		if (this.status == StatusPagina.LISTAR) {
			return true;
		}
		return false;
	}

	public boolean isCRUDRendered() {
		return !isListagemRendered();
	}

	public boolean isOpcaoAtivarDisabled() {
		if (registroSelecionado == null) {
			return true;
		}

		if (this.registroSelecionado.getAtivo()) {
			return true;
		}

		return false;
	}

	public boolean isOpcaoInativarDisabled() {
		if (registroSelecionado == null) {
			return true;
		}

		return !isOpcaoAtivarDisabled();
	}

	public void acessarPaginaEdicao(ActionEvent event) {
		status = StatusPagina.EDITAR;
		procedimentosAntesAcessarCRUD();

		registrosEncontrados = null;
	}

	public Integer getQuantidadeRegistrosPorPagina() {
		return quantidadeRegistrosPorPagina;
	}

	public void setQuantidadeRegistrosPorPagina(Integer quantidadeRegistrosPorPagina) {
		this.quantidadeRegistrosPorPagina = quantidadeRegistrosPorPagina;
	}

	public Integer getPaginaAtual() {
		return paginaAtual;
	}

	public void setPaginaAtual(Integer paginaAtual) {
		this.paginaAtual = paginaAtual;
	}

	public T getRegistroSelecionado() {
		return registroSelecionado;
	}

	public void setRegistroSelecionado(T registroSelecionado) {
		this.registroSelecionado = registroSelecionado;
	}

	public List<T> getRegistrosEncontrados() {
		return registrosEncontrados;
	}

	public void setNavegacaoSession(UsuarioNavegacaoSession navegacaoSession) {
		this.navegacaoSession = navegacaoSession;
	}

	public void setNegocio(AbstractNegocio<T, PK> negocio) {
		this.negocio = negocio;
	}

	public Long getQuantidadeRegistrosEncontrados() {
		return quantidadeRegistrosEncontrados;
	}

	public Long getQuantidadeRegistrosAtivos() {
		return quantidadeRegistrosAtivos;
	}

	public Long getQuantidadeRegistrosInativos() {
		return quantidadeRegistrosInativos;
	}

	public void setCrudSession(CRUDSession crudSession) {
		this.crudSession = crudSession;
	}

	public Class<T> getClasse() {
		return classe;
	}

	public StatusPagina getStatus() {
		return status;
	}

	public Panel getFiltragem() {
		return filtragem;
	}

	public void setFiltragem(Panel filtragem) {
		this.filtragem = filtragem;
	}

	public SelectOneMenu getSelectOneMenu() {
		return selectOneMenu;
	}

	public void setSelectOneMenu(SelectOneMenu selectOneMenu) {
		this.selectOneMenu = selectOneMenu;

		selectOneMenu.getAttributes();
		selectOneMenu.getChildren();
	}
}
